namespace classifier_test
{

namespace high_order
{

class stream_predictor : public virtual virtual_object, private noncopyable
{
public:
	struct chunk
	{
		int begin, end;
		int concept;
	};
	struct concept
	{
		smart_ptr<classifier_test::classifier> classifier;
		double verror;

		void serialize(serializer& Serializer);
	};

	stream_predictor();
	stream_predictor(const stream_predictor& Val);
	virtual smart_ptr<stream_predictor> clone() const = 0;
	virtual void serialize(serializer& Serializer);
	virtual void initialize_options(command_line_options& Options) const;
	virtual void apply_arguments(const command_line_arguments& Args);
	const record_domain& get_domain() const;
	virtual void set_domain(const record_domain& Val);
	classifier* get_base_classifier() const;
	virtual void set_base_classifier(classifier* Val);

	virtual void set_stream(subarray<const record* const> Data) = 0;
	virtual void set_chunk_count(int Val) = 0;
	virtual void set_chunk(int I, int Begin, int End, int Concept) = 0;
	virtual void set_concept_count(int Val) = 0;
	virtual void set_concept(int I, smart_ptr<validation_dataset> VDataset, smart_ptr<validation_classifier> VClassifier, double VError) = 0;
	virtual void compute() = 0;

	virtual void train(const record& Record) = 0;
	virtual discr_value classify(const stream_record& Record) const = 0;
	virtual void estimate(const stream_record& Record, array<double>& Probs) const = 0;
	virtual int get_concept_count() const = 0;
	virtual const array<double>& get_state_probabilities() const = 0;

protected:
	record_domain Domain;
	int ClassCount;
	smart_ptr<classifier> BaseClassifier;
};

class high_order_stream_predictor : public stream_predictor
{
public:
	high_order_stream_predictor();
	high_order_stream_predictor(const high_order_stream_predictor& Val);
	smart_ptr<stream_predictor> clone() const;
	void serialize(serializer& Serializer);

	void set_stream(subarray<const record* const> Data);
	void set_chunk_count(int Val);
	void set_chunk(int I, int Begin, int End, int Concept);
	void set_concept_count(int Val);
	void set_concept(int I, smart_ptr<validation_dataset> VDataset, smart_ptr<validation_classifier> VClassifier, double VError);
	void compute();

	void train(const record& Record);
	discr_value classify(const stream_record& Record) const;
	void estimate(const stream_record& Record, array<double>& Probs) const;
	int get_concept_count() const;
	const array<double>& get_state_probabilities() const;

private:
	struct my_concept : public concept
	{
		int occur_freq, length;
		double end_prob;
		
		void serialize(serializer& Serializer);
	};
	subarray<const record* const> Stream;
	vector<chunk> Chunks;
	vector<my_concept> Concepts;
	array<double> StateProbs;

	void compute_transitions();
	void update_states_by_data(const record& Rec);
	void update_states_by_time();
};

}

}
